

#include "URL.h"
#include <iostream>
#include <list>
#include <map>
#include <ext/hash_map>
#include "URLFileDealer.h"
#include <boost/tr1/memory.hpp>
#include <boost/thread/mutex.hpp>

#include "../classes_dados/Hasher.h"
#include "../classes_dados/URLDiskClass.h"


using namespace std;
using namespace __gnu_cxx;

std::tr1::shared_ptr<URLFileDealer> URLFileDealer::theURLFileDealer(new URLFileDealer);



void URLFileDealer::addToDiskBuffer(URL * url){
	list<URL *>::iterator itp;
	boost::mutex::scoped_lock diskBufferLock(diskBufferMutex);
	toDiskBuffer.push_back(url);
	uint tempTamanho = toDiskBuffer.size();
	// se a lista de escrita atinge tamanho maximo, grava no disco
	if(tempTamanho > Config::getMaxNumUrlsFromDisk()){
		//coloca de forma a evitar conflito de 30 seg
		uint pulo = 250;
		for(uint i=0; i<pulo; i++)
			for(uint j=i; j < tempTamanho; j+=pulo ){
				discoUrl.writeDisk(*toDiskBuffer[j]);
				delete toDiskBuffer[j];
			}
		toDiskBuffer.clear();
	}
	
}


list<URL *> URLFileDealer::getNewURLs() {

	list<URL *>::iterator it;
	list<URL *> tempList;
	URL * tempUrl;

	long long tamanho = discoUrl.totalNewURLs();
	
	
	if(tamanho > 0){
		if(tamanho > maxNumUrlsFromDisk) tamanho = maxNumUrlsFromDisk;  // limita tamanho		
		for (long long i = 0; i<tamanho; i++) {
			tempUrl = new URL( discoUrl.readDisk() );
			tempList.push_back(tempUrl);
		}
	}else{
		// se aqui, disco vazio....
		// pega lista esperando para ser gravada e grava, e executa a leitura
		{
		boost::mutex::scoped_lock diskBufferLock(diskBufferMutex);
		//grava de forma a evitar conflito de 30 seg
		uint tempTamanho = toDiskBuffer.size();
		uint pulo = 250;
		for(uint i=0; i<pulo; i++)
			for(uint j=i; j < tempTamanho; j+=pulo ){
				discoUrl.writeDisk(*toDiskBuffer[j]);
				delete toDiskBuffer[j];
			}
		
		toDiskBuffer.clear(); //limpa lista que foi gravada		
		}
		tamanho = discoUrl.totalNewURLs();
		
		if(tamanho > 0){
			if(tamanho > maxNumUrlsFromDisk) tamanho = maxNumUrlsFromDisk;
			for (long long i = 0; i<tamanho; i++){
				tempUrl = new URL( discoUrl.readDisk() );;
				tempList.push_back(tempUrl);
			}
		}else cout << "Tamanho continuou zero... " << endl;
	}
	
	return tempList;
}


void URLFileDealer::initURLHashSet(unsigned long long urlHash){
	boost::mutex::scoped_lock urlHashSetLock(urlHashSetMutex);
	urlHashMap[urlHash] = true;	
}


void URLFileDealer::addURLs(std::list<URL> urlList){

	unsigned long long urlHash;
	list<URL>::const_iterator it;
	
	// adiciona lista de entrada na lista de URL para escrita;
	for (it = urlList.begin(); it!=urlList.end(); it++) {

		urlHash = Hasher::hash64FromString(it->toString());
		boost::mutex::scoped_lock urlHashSetLock(urlHashSetMutex);
		
		if  (!urlHashMap[urlHash]){         //verifica se tem 
			urlHashMap[urlHash] = true;     //marca que agora tem
			addToDiskBuffer(new URL(*it));
			//Estrutura para Backup
			writeHashFile(urlHash);			
			
		}		
	}

}


void URLFileDealer::writeHashFile(unsigned long long hash_in){
	boost::mutex::scoped_lock hashFileLock(readHashFileMutex);
	t_hashFile << hash_in << endl;

}


long long URLFileDealer::faltanteNoDiscoZero(void){
	return (discoUrl.size(0) - discoUrl.pos(0));
}



